home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / book / Chap06 / Shadow / Shadow.c next >
Encoding:
C/C++ Source or Header  |  1999-09-03  |  13.7 KB  |  560 lines

  1. // Shadow.c
  2. // OpenGL SuperBible, Chapter 6
  3. // Demonstrates simple planar shadows
  4. // Program by Richard S. Wright Jr.
  5.  
  6. #include <windows.h>
  7. #include <gl/gl.h>
  8. #include <gl/glu.h>
  9. #include <gl/glut.h>
  10. #include <math.h>
  11.  
  12.  
  13. // Define a constant for the value of PI
  14. #define GL_PI 3.1415f
  15.  
  16. // Rotation amounts
  17. static GLfloat xRot = 0.0f;
  18. static GLfloat yRot = 0.0f;
  19.  
  20. // These values need to be available globally
  21. // Light values and coordinates
  22. GLfloat  ambientLight[] = { 0.3f, 0.3f, 0.3f, 1.0f };
  23. GLfloat  diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };
  24. GLfloat  specular[] = { 1.0f, 1.0f, 1.0f, 1.0f};
  25. GLfloat     lightPos[] = { -75.0f, 150.0f, -50.0f, 0.0f };
  26. GLfloat  specref[] =  { 1.0f, 1.0f, 1.0f, 1.0f };
  27.  
  28. // Transformation matrix to project shadow
  29. GLfloat shadowMat[4][4];
  30.  
  31.  
  32. // Reduces a normal vector specified as a set of three coordinates,
  33. // to a unit normal vector of length one.
  34. void ReduceToUnit(float vector[3])
  35.     {
  36.     float length;
  37.     
  38.     // Calculate the length of the vector        
  39.     length = (float)sqrt((vector[0]*vector[0]) + 
  40.                         (vector[1]*vector[1]) +
  41.                         (vector[2]*vector[2]));
  42.  
  43.     // Keep the program from blowing up by providing an exceptable
  44.     // value for vectors that may calculated too close to zero.
  45.     if(length == 0.0f)
  46.         length = 1.0f;
  47.  
  48.     // Dividing each element by the length will result in a
  49.     // unit normal vector.
  50.     vector[0] /= length;
  51.     vector[1] /= length;
  52.     vector[2] /= length;
  53.     }
  54.  
  55.  
  56. // Points p1, p2, & p3 specified in counter clock-wise order
  57. void calcNormal(float v[3][3], float out[3])
  58.     {
  59.     float v1[3],v2[3];
  60.     static const int x = 0;
  61.     static const int y = 1;
  62.     static const int z = 2;
  63.  
  64.     // Calculate two vectors from the three points
  65.     v1[x] = v[0][x] - v[1][x];
  66.     v1[y] = v[0][y] - v[1][y];
  67.     v1[z] = v[0][z] - v[1][z];
  68.  
  69.     v2[x] = v[1][x] - v[2][x];
  70.     v2[y] = v[1][y] - v[2][y];
  71.     v2[z] = v[1][z] - v[2][z];
  72.  
  73.     // Take the cross product of the two vectors to get
  74.     // the normal vector which will be stored in out
  75.     out[x] = v1[y]*v2[z] - v1[z]*v2[y];
  76.     out[y] = v1[z]*v2[x] - v1[x]*v2[z];
  77.     out[z] = v1[x]*v2[y] - v1[y]*v2[x];
  78.  
  79.     // Normalize the vector (shorten length to one)
  80.     ReduceToUnit(out);
  81.     }
  82.  
  83. // Creates a shadow projection matrix out of the plane equation
  84. // coefficients and the position of the light. The return value is stored
  85. // in destMat[][]
  86. void MakeShadowMatrix(GLfloat points[3][3], GLfloat lightPos[4], GLfloat destMat[4][4])
  87.     {
  88.     GLfloat planeCoeff[4];
  89.     GLfloat dot;
  90.  
  91.     // Find the plane equation coefficients
  92.     // Find the first three coefficients the same way we
  93.     // find a normal.
  94.     calcNormal(points,planeCoeff);
  95.  
  96.     // Find the last coefficient by back substitutions
  97.     planeCoeff[3] = - (
  98.         (planeCoeff[0]*points[2][0]) + (planeCoeff[1]*points[2][1]) +
  99.         (planeCoeff[2]*points[2][2]));
  100.  
  101.  
  102.     // Dot product of plane and light position
  103.     dot = planeCoeff[0] * lightPos[0] +
  104.             planeCoeff[1] * lightPos[1] +
  105.             planeCoeff[2] * lightPos[2] +
  106.             planeCoeff[3] * lightPos[3];
  107.  
  108.     // Now do the projection
  109.     // First column
  110.     destMat[0][0] = dot - lightPos[0] * planeCoeff[0];
  111.     destMat[1][0] = 0.0f - lightPos[0] * planeCoeff[1];
  112.     destMat[2][0] = 0.0f - lightPos[0] * planeCoeff[2];
  113.     destMat[3][0] = 0.0f - lightPos[0] * planeCoeff[3];
  114.  
  115.     // Second column
  116.     destMat[0][1] = 0.0f - lightPos[1] * planeCoeff[0];
  117.     destMat[1][1] = dot - lightPos[1] * planeCoeff[1];
  118.     destMat[2][1] = 0.0f - lightPos[1] * planeCoeff[2];
  119.     destMat[3][1] = 0.0f - lightPos[1] * planeCoeff[3];
  120.  
  121.     // Third Column
  122.     destMat[0][2] = 0.0f - lightPos[2] * planeCoeff[0];
  123.     destMat[1][2] = 0.0f - lightPos[2] * planeCoeff[1];
  124.     destMat[2][2] = dot - lightPos[2] * planeCoeff[2];
  125.     destMat[3][2] = 0.0f - lightPos[2] * planeCoeff[3];
  126.  
  127.     // Fourth Column
  128.     destMat[0][3] = 0.0f - lightPos[3] * planeCoeff[0];
  129.     destMat[1][3] = 0.0f - lightPos[3] * planeCoeff[1];
  130.     destMat[2][3] = 0.0f - lightPos[3] * planeCoeff[2];
  131.     destMat[3][3] = dot - lightPos[3] * planeCoeff[3];
  132.     }
  133.  
  134.  
  135. ////////////////////////////////////////////////
  136. // This function just specifically draws the jet
  137. void DrawJet(BOOL bShadow)
  138.     {
  139.     float normal[3];    // Storeage for calculated surface normal
  140.  
  141.     // Nose Cone /////////////////////////////
  142.     // Set material color, note we only have to set to black
  143.     // for the shadow once
  144.     if(!bShadow)
  145.         glColor3ub(0, 255, 0);
  146.     else
  147.         glColor3ub(0,0,0);
  148.  
  149.  
  150.     glBegin(GL_TRIANGLES);
  151.         glNormal3f(0.0f, -1.0f, 0.0f);
  152.         glVertex3f(0.0f, 0.0f, 60.0f);
  153.         glVertex3f(-15.0f, 0.0f, 30.0f);
  154.         glVertex3f(15.0f,0.0f,30.0f);
  155.  
  156.         {
  157.         // Verticies for this panel
  158.         static float v[3][3] =    {{ 15.0f, 0.0f, 30.0f},
  159.                         { 0.0f, 15.0f, 30.0f},
  160.                         { 0.0f, 0.0f,    60.0f}};
  161.  
  162.         // Calculate the normal for the plane
  163.         calcNormal(v,normal);
  164.  
  165.         // Draw the triangle using the plane normal
  166.         // for all the vertices
  167.             glNormal3fv(normal);
  168.             glVertex3fv(v[0]);
  169.             glVertex3fv(v[1]);
  170.             glVertex3fv(v[2]);
  171.         }    
  172.  
  173.         {
  174.         static float v[3][3] = {{ 0.0f, 0.0f, 60.0f },
  175.                          { 0.0f, 15.0f, 30.0f },
  176.                          { -15.0f, 0.0f, 30.0f }};
  177.  
  178.         calcNormal(v,normal);
  179.  
  180.             glNormal3fv(normal);
  181.             glVertex3fv(v[0]);
  182.             glVertex3fv(v[1]);
  183.             glVertex3fv(v[2]);
  184.         }
  185.  
  186.  
  187.  
  188.         // Body of the Plane ////////////////////////
  189.         // light gray
  190.         if(!bShadow)
  191.             glColor3ub(192,192,192);
  192.         {
  193.         static float v[3][3] = {{ -15.0f,0.0f,30.0f },
  194.                      { 0.0f, 15.0f, 30.0f },
  195.                      { 0.0f, 0.0f, -56.0f }};
  196.  
  197.         calcNormal(v,normal);
  198.             glNormal3fv(normal);
  199.             glVertex3fv(v[0]);
  200.             glVertex3fv(v[1]);
  201.             glVertex3fv(v[2]);
  202.         }
  203.         
  204.         {
  205.         static float v[3][3] = {{ 0.0f, 0.0f, -56.0f },
  206.                          { 0.0f, 15.0f, 30.0f },
  207.                          { 15.0f,0.0f,30.0f }};
  208.         calcNormal(v,normal);
  209.             glNormal3fv(normal);
  210.             glVertex3fv(v[0]);
  211.             glVertex3fv(v[1]);
  212.             glVertex3fv(v[2]);    
  213.         }
  214.         
  215.             
  216.             glNormal3f(0.0f, -1.0f, 0.0f);
  217.             glVertex3f(15.0f,0.0f,30.0f);
  218.             glVertex3f(-15.0f, 0.0f, 30.0f);
  219.             glVertex3f(0.0f, 0.0f, -56.0f);
  220.  
  221.  
  222.         ///////////////////////////////////////////////
  223.         // Left wing
  224.         // Large triangle for bottom of wing
  225.         // Dark gray
  226.  
  227.         // Set drawing color
  228.         if(!bShadow)
  229.             glColor3ub(128,128,128);
  230.         {
  231.         static float v[3][3] = {{ 0.0f,2.0f,27.0f },
  232.                      { -60.0f, 2.0f, -8.0f },
  233.                      { 60.0f, 2.0f, -8.0f }};
  234.  
  235.         // Calculate the normal from the verticies
  236.         calcNormal(v,normal);
  237.  
  238.             glNormal3fv(normal);
  239.             glVertex3fv(v[0]);
  240.             glVertex3fv(v[1]);
  241.             glVertex3fv(v[2]);
  242.         }
  243.         
  244.         {
  245.         static float v[3][3] =    {{ 60.0f, 2.0f, -8.0f},
  246.                         {0.0f, 7.0f, -8.0f},
  247.                         {0.0f,2.0f,27.0f }};
  248.  
  249.         calcNormal(v,normal);
  250.  
  251.             glNormal3fv(normal);
  252.             glVertex3fv(v[0]);
  253.             glVertex3fv(v[1]);
  254.             glVertex3fv(v[2]);
  255.         }
  256.  
  257.         {
  258.         static float v[3][3] = {{60.0f, 2.0f, -8.0f},
  259.                         {-60.0f, 2.0f, -8.0f},
  260.                         {0.0f,7.0f,-8.0f }};
  261.  
  262.         calcNormal(v,normal);
  263.  
  264.             glNormal3fv(normal);
  265.             glVertex3fv(v[0]);
  266.             glVertex3fv(v[1]);
  267.             glVertex3fv(v[2]);
  268.         }
  269.  
  270.         {
  271.         static float v[3][3] = {{0.0f,2.0f,27.0f},
  272.                          {0.0f, 7.0f, -8.0f},
  273.                          {-60.0f, 2.0f, -8.0f}};
  274.  
  275.         calcNormal(v,normal);
  276.         
  277.         // Other wing top section
  278.             glNormal3fv(normal);
  279.             glVertex3fv(v[0]);
  280.             glVertex3fv(v[1]);
  281.             glVertex3fv(v[2]);
  282.         }
  283.  
  284.  
  285.         // Tail section///////////////////////////////
  286.         // Bottom of back fin
  287.         if(!bShadow)
  288.             glColor3ub(255,255,0);
  289.         
  290.             glNormal3f(0.0f, -1.0f, 0.0f);
  291.             glVertex3f(-30.0f, -0.50f, -57.0f);
  292.             glVertex3f(30.0f, -0.50f, -57.0f);
  293.             glVertex3f(0.0f,-0.50f,-40.0f);
  294.  
  295.         {
  296.         static float v[3][3] = {{ 0.0f,-0.5f,-40.0f },
  297.                         {30.0f, -0.5f, -57.0f},
  298.                         {0.0f, 4.0f, -57.0f }};
  299.  
  300.         calcNormal(v,normal);
  301.  
  302.         // top of left side
  303.             glNormal3fv(normal);
  304.             glVertex3fv(v[0]);
  305.             glVertex3fv(v[1]);
  306.             glVertex3fv(v[2]);
  307.         }
  308.  
  309.         {
  310.         static float v[3][3] = {{ 0.0f, 4.0f, -57.0f },
  311.                         { -30.0f, -0.5f, -57.0f },
  312.                         { 0.0f,-0.5f,-40.0f }};
  313.  
  314.         calcNormal(v,normal);
  315.  
  316.         // top of right side
  317.             glNormal3fv(normal);
  318.             glVertex3fv(v[0]);
  319.             glVertex3fv(v[1]);
  320.             glVertex3fv(v[2]);
  321.         }
  322.  
  323.         {
  324.         static float v[3][3] = {{ 30.0f,-0.5f,-57.0f },
  325.                         { -30.0f, -0.5f, -57.0f },
  326.                         { 0.0f, 4.0f, -57.0f }};
  327.  
  328.         calcNormal(v,normal);
  329.  
  330.         // back of bottom of tail
  331.             glNormal3fv(normal);
  332.             glVertex3fv(v[0]);
  333.             glVertex3fv(v[1]);
  334.             glVertex3fv(v[2]);
  335.         }
  336.  
  337.         {
  338.         static float v[3][3] = {{ 0.0f,0.5f,-40.0f },
  339.                         { 3.0f, 0.5f, -57.0f },
  340.                         { 0.0f, 25.0f, -65.0f }};
  341.  
  342.         calcNormal(v,normal);
  343.  
  344.         // Top of Tail section left
  345.         if(!bShadow)
  346.             glColor3ub(255,0,0);
  347.         
  348.             glNormal3fv(normal);
  349.             glVertex3fv(v[0]);
  350.             glVertex3fv(v[1]);
  351.             glVertex3fv(v[2]);
  352.         }
  353.  
  354.         {
  355.         static float v[3][3] = {{ 0.0f, 25.0f, -65.0f },
  356.                         { -3.0f, 0.5f, -57.0f},
  357.                         { 0.0f,0.5f,-40.0f }};
  358.  
  359.         calcNormal(v,normal);
  360.  
  361.             glNormal3fv(normal);
  362.             glVertex3fv(v[0]);
  363.             glVertex3fv(v[1]);
  364.             glVertex3fv(v[2]);
  365.         }
  366.  
  367.         {
  368.         static float v[3][3] = {{ 3.0f,0.5f,-57.0f },
  369.                         { -3.0f, 0.5f, -57.0f },
  370.                         { 0.0f, 25.0f, -65.0f }};
  371.  
  372.         calcNormal(v,normal);
  373.  
  374.         // Back of horizontal section
  375.             glNormal3fv(normal);
  376.             glVertex3fv(v[0]);
  377.             glVertex3fv(v[1]);
  378.             glVertex3fv(v[2]);
  379.         glEnd();
  380.         }
  381.     }
  382.  
  383. // Called to draw scene
  384. void RenderScene(void)
  385.     {
  386.     // Clear the window with current clearing color
  387.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  388.  
  389.     // Draw the ground, we do manual shading to a darker green
  390.     // in the background to give the illusion of depth
  391.     glBegin(GL_QUADS);
  392.         glColor3ub(0,32,0);
  393.         glVertex3f(400.0f, -150.0f, -200.0f);
  394.         glVertex3f(-400.0f, -150.0f, -200.0f);
  395.         glColor3ub(0,255,0);
  396.         glVertex3f(-400.0f, -150.0f, 200.0f);
  397.         glVertex3f(400.0f, -150.0f, 200.0f);
  398.     glEnd();
  399.  
  400.     // Save the matrix state and do the rotations
  401.     glPushMatrix();
  402.  
  403.     // Draw jet at new orientation, put light in correct position
  404.     // before rotating the jet
  405.     glEnable(GL_LIGHTING);
  406.     glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
  407.     glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  408.     glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  409.  
  410.     DrawJet(FALSE);
  411.  
  412.     // Restore original matrix state
  413.     glPopMatrix();    
  414.  
  415.  
  416.     // Get ready to draw the shadow and the ground
  417.     // First disable lighting and save the projection state
  418.     glDisable(GL_DEPTH_TEST);
  419.     glDisable(GL_LIGHTING);
  420.     glPushMatrix();
  421.  
  422.     // Multiply by shadow projection matrix
  423.     glMultMatrixf((GLfloat *)shadowMat);
  424.  
  425.     // Now rotate the jet around in the new flattend space
  426.     glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  427.     glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  428.  
  429.     // Pass true to indicate drawing shadow
  430.     DrawJet(TRUE);    
  431.  
  432.     // Restore the projection to normal
  433.     glPopMatrix();
  434.  
  435.     // Draw the light source
  436.     glPushMatrix();
  437.     glTranslatef(lightPos[0],lightPos[1], lightPos[2]);
  438.     glColor3ub(255,255,0);
  439.     glutSolidSphere(5.0f,10,10);
  440.     glPopMatrix();
  441.  
  442.     // Restore lighting state variables
  443.     glEnable(GL_DEPTH_TEST);
  444.  
  445.     // Display the results
  446.     glutSwapBuffers();
  447.     }
  448.  
  449. // This function does any needed initialization on the rendering
  450. // context. 
  451. void SetupRC()
  452.     {
  453.     // Any three points on the ground (counter clockwise order)
  454.     GLfloat points[3][3] = {{ -30.0f, -149.0f, -20.0f },
  455.                             { -30.0f, -149.0f, 20.0f },
  456.                             { 40.0f, -149.0f, 20.0f }};
  457.  
  458.     glEnable(GL_DEPTH_TEST);    // Hidden surface removal
  459.     glFrontFace(GL_CCW);        // Counter clock-wise polygons face out
  460.     glEnable(GL_CULL_FACE);        // Do not calculate inside of jet
  461.  
  462.     // Setup and enable light 0
  463.     glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
  464.     glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
  465.     glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
  466.     glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
  467.     glEnable(GL_LIGHT0);
  468.  
  469.     // Enable color tracking
  470.     glEnable(GL_COLOR_MATERIAL);
  471.     
  472.     // Set Material properties to follow glColor values
  473.     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  474.  
  475.     // All materials hereafter have full specular reflectivity
  476.     // with a high shine
  477.     glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
  478.     glMateriali(GL_FRONT,GL_SHININESS,128);
  479.  
  480.     // Light blue background
  481.     glClearColor(0.0f, 0.0f, 1.0f, 1.0f );
  482.  
  483.     // Calculate projection matrix to draw shadow on the ground
  484.     MakeShadowMatrix(points, lightPos, shadowMat);
  485.     }
  486.  
  487. void SpecialKeys(int key, int x, int y)
  488.     {
  489.     if(key == GLUT_KEY_UP)
  490.         xRot-= 5.0f;
  491.  
  492.     if(key == GLUT_KEY_DOWN)
  493.         xRot += 5.0f;
  494.  
  495.     if(key == GLUT_KEY_LEFT)
  496.         yRot -= 5.0f;
  497.  
  498.     if(key == GLUT_KEY_RIGHT)
  499.         yRot += 5.0f;
  500.  
  501.     if(key > 356.0f)
  502.         xRot = 0.0f;
  503.  
  504.     if(key < -1.0f)
  505.         xRot = 355.0f;
  506.  
  507.     if(key > 356.0f)
  508.         yRot = 0.0f;
  509.  
  510.     if(key < -1.0f)
  511.         yRot = 355.0f;
  512.  
  513.     // Refresh the Window
  514.     glutPostRedisplay();
  515.     }
  516.  
  517.  
  518. void ChangeSize(int w, int h)
  519.     {
  520.     GLfloat nRange = 200.0f;
  521.     GLfloat fAspect;
  522.  
  523.     // Prevent a divide by zero
  524.     if(h == 0)
  525.         h = 1;
  526.  
  527.     
  528.     // Set Viewport to window dimensions
  529.     glViewport(0, 0, w, h);
  530.  
  531.     // Reset coordinate system
  532.     glMatrixMode(GL_PROJECTION);
  533.     glLoadIdentity();
  534.  
  535.     fAspect = (GLfloat)w/(GLfloat)h;
  536.  
  537.     gluPerspective(60.0f, fAspect, 1.0, 500.0);
  538.  
  539.     glMatrixMode(GL_MODELVIEW);
  540.     glLoadIdentity();
  541.  
  542.     // Move out Z axis so we can see everything
  543.     glTranslatef(0.0f, 0.0f, -400.0f);
  544.     glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
  545.     }
  546.  
  547. int main(int argc, char* argv[])
  548.     {
  549.     glutInit(&argc, argv);
  550.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  551.     glutCreateWindow("Shadow");
  552.     glutReshapeFunc(ChangeSize);
  553.     glutSpecialFunc(SpecialKeys);
  554.     glutDisplayFunc(RenderScene);
  555.     SetupRC();
  556.     glutMainLoop();
  557.  
  558.     return 0;
  559.     }
  560.